#!/usr/bin/python
# This file is part of ModularBot.
# Copyright (C) 2005 Pierre Ducroquet (pierre.linux59@wanadoo.fr)

# ModularBot is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# ModularBot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with ModularBot; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import socket, time, sys

class IRCClient:
	def __init__ (self, host, port, nick, ident, realname, bind):
		for var in ["host", "port", "nick", "ident", "realname", "bind"]:
			setattr(self, var, locals()[var])
		self.nickname = nick
		self.sock = socket.socket()
		self.versionString = "modularbot"
	
	def IRC_send (self, txt):
		self.sock.send("%s\r\n" % txt)
	
	def connect (self):
		for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM):
			af, socktype, proto, canonname, sa = res
			try:
				self.sock = socket.socket(af, socktype, proto)
			except socket.error, msg:
				self.sock = None
				continue
			try:
				if self.bind != "":
					self.sock.bind((self.bind, 0))
				self.sock.connect(sa)
			except socket.error, msg:
				self.sock.close()
				self.sock = None
				continue
			break
		if not self.sock:
			print "Could not open socket"
			sys.exit(1)
		self.sock.settimeout(90)
		self.IRC_send("NICK %s" % self.nickname)
		self.IRC_send("USER %s %s bla :%s" % (self.ident, self.host, self.realname))
	
	def join (self, channel):
		self.IRC_send("JOIN %s" % channel)
		self.joined(channel)
	
	def leave (self, channel, reason):
		self.IRC_send("PART %s :%s" % (channel, reason))
	
	def privmsg (self, user, channel, msg):
		pass
	
	#def say (self, channel, msg):
		#self.floodmgr.send((channel, msg, False))
	
	def say (self, channel, msg):
		self.IRC_send("PRIVMSG %s :%s" % (channel, msg))
	
	#def notice (self, channel, msg):
		#self.floodmgr.send((channel, msg, True))
	
	def notice (self, channel, msg):
		self.IRC_send("NOTICE %s :%s" % (channel, msg))
	
	def CTCP_PING (self, user, msg):
		self.notice(user[:user.find("!")], msg)
	
	def CTCP_VERSION (self, user, msg):
		print "CTCP VERSION"
		self.notice(user[:user.find("!")], msg.replace("VERSION", "VERSION %s" % self.versionString))
	
	def PRIVMSG (self, line, line_splitted):
		channel = line_splitted[2]
		user = line_splitted[0][1:]
		msg = line[len(user) + len(channel) + len(line_splitted[1]) + 5:]
		if msg[0] == chr(1) and msg[-1] == chr(1):
			ctcp_cmd = msg[1:-1].split(" ", 1)[0]
			if hasattr(self, "CTCP_" + ctcp_cmd):
				getattr(self, "CTCP_" + ctcp_cmd)(user, msg)
			else:
				print "CTCP command %s not found" % ctcp_cmd
		else:
			self.privmsg(user, channel, msg)
	
	def KICK (self, line, line_splitted):
		channel = line_splitted[2]
		kicked = line_splitted[3]
		kicker = line_splitted[0][1:]
		msg = line[len(kicker) + len(channel) + len(line_splitted[1]) + len(kicked) + 6:]
		self.userKicked(kicked, channel, kicker, msg)
	
	def JOIN (self, line, line_splitted):
		channel = line_splitted[2][1:]
		user = line_splitted[0][1:]
		self.userJoined(user, channel)
	
	def NICK (self, line, line_splitted):
		oldname = line_splitted[0][1:]
		oldname = oldname[:oldname.find("!")]
		newname = line[line.rfind(":")+1:]
		self.userRenamed (oldname, newname)
	
	def PART (self, line, line_splitted):
		channel = line_splitted[2]
		user = line_splitted[0][1:]
		self.userLeft(user, channel)
	
	def MODE (self, line, line_splitted):
		# :PieD!n=Pierre@ALille-251-1-68-187.w82-127.abo.wanadoo.fr MODE #fnux +o Dictator5
		channel = line_splitted[2]
		user = line_splitted[0][1:line_splitted[0].find("!")]
		set = line_splitted[3].startswith("+")
		modes = line_splitted[3][1:]
		args = line[line.find(line_splitted[3]):]
		print line
		print line_splitted
		print (user, channel, set, modes, args)
		self.modeChanged(user, channel, set, modes, args)
	
	def run (self):
		readbuffer = ""
		sent_ping = False
		while 1:
			try:
				readbuffer = readbuffer + self.sock.recv (1024)
				try:
					temp = readbuffer.split ("\n")
					readbuffer = temp.pop ()
					for line in temp:
						line = line.rstrip()
						if not "login" in line: print line
						line_splitted = line.split()
						if line_splitted[0] == "PING":
							self.IRC_send ("PONG %s" % line_splitted[1])
						elif line_splitted[1] == "PONG":
							sent_ping = False
						else:
							if hasattr(self, line_splitted[1]):
								getattr(self, line_splitted[1])(line, line_splitted)
							else:
								try:
									cmd_number = int(line_splitted[1])
									if cmd_number == 376 or cmd_number == 422: #end of motd || motd missing ==> We're logged in to the server
										self.signedOn()
									self.numericAnswer(cmd_number, line.split(" ", 3)[-1])
								except ValueError:
									pass
								#print "Unknown IRC command !!!!"
				except:
					sys.excepthook(*sys.exc_info())
			except socket.timeout:
				if not sent_ping:
					self.IRC_send("PING %s;" % self.host)
					sent_ping = True
				else:
					raise
	
	#EVENTS :
	def signedOn(self):
		pass
	
	def joined(self, channel):
		pass

	def userKicked(self, user, channel, kicker, reason):
		pass
	
	def userJoined(self, user, channel):
		pass
	
	def userRenamed(self, oldname, newname):
		pass

	def userLeft(self, user, channel):
		pass
	
	def numericAnswer(self, cmd_number, line):
		pass
